<?php
include "dataHandlerClass.php";
include "elementHandlerClass.php";
include "structHandlerClass.php";
include "relationHandlerClass.php";
include_once "xmllib.php";

/*
 * CONFIGURATION CONSTANTS
*/
define("SEPARATOR",'/');
define("ID_SEPARATOR",'-');
define("ROOT_NAME",'/SISTEMA');
define("DATA_TABLENAME","block_modulo_control_tutorial_data");
define("STRUCT_TABLENAME","block_modulo_control_tutorial_structure");
define("ELEMENTS_TABLENAME","block_modulo_control_tutorial_elements");
define("INTERNAL_NODES_TYPE_NAME","NODE");
define("ELEMENT_NODES_TYPE_NAME","ELEMENT");
define("VALUE_TYPES","INTEGER,STRING,DATE,REAL,BOOLEAN");

//Regular expression to handle the name of the nodes.
define("NODES_NAME_REGEX",'/^[a-zd_-]{1,80}[0-9]{0,10}$/i');
//Regular expression to handle the name of the elements.
define("ELEMENTS_NAME_REGEX",'/^([-a-z0-9_-])+$/i');

/**
 * This class contains the functions to manage the data model based in Nested Set Model.
 * This file contains the constants to config the model.
 */
class Model {
    public $parametros;
    public $gestorDatos;
    public $gestorElementos;
    public $gestorEstructura;
    public $gestorRelaciones;

    /**
     * This function loads the configuration parameters from the constants defined before.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     */
    function __construct($debug=false) {
        $this->parametros=array();
        $this->parametros['id_char']=ID_SEPARATOR;
        $this->parametros['root_name']=ROOT_NAME;
        $this->parametros['internal_nodes_type_name']=INTERNAL_NODES_TYPE_NAME;
        $this->parametros['element_nodes_type_name']=ELEMENT_NODES_TYPE_NAME;
        $this->parametros['value_types']=VALUE_TYPES;
        $this->parametros['nodes_name_regex']=NODES_NAME_REGEX;
        $this->parametros['elements_name_regex']=ELEMENTS_NAME_REGEX;
        $this->parametros['separator']=SEPARATOR;

        $this->gestorEstructura= new StructHandler("pru_".STRUCT_TABLENAME, $this->parametros, $debug);
        $this->gestorElementos=new ElementHandler("pru_".ELEMENTS_TABLENAME,$this->parametros,$debug);
        $this->gestorDatos=new DataHandler("pru_".DATA_TABLENAME, $this->parametros,$debug);
        $this->gestorRelaciones=new RelationHandler("pru_".ELEMENTS_TABLENAME, $this->parametros, $debug);
        $this->gestorXML = new XMLHandler($this->parametros);
    }

    /**
     *This function will load the structure from the XML into the database
     * @param <bool> $debug True to debug the function
     */
    function loadStructure($debug=false) {
        $array = $this->gestorXML->getArrayStruct();
        foreach ($array as $element) {
            if ($this->addChild($element->getValue(),$element->getType(), $element->getParentName(),$element->getBrotherName(),$debug)) ;
        }
    }

    function removeFirstSlash($string) {
        return $newarray = substr($string,1);
    }

    function getTypeStruct($name){
        return $this->gestorEstructura->getType($name);
    }

    function getAllowedTypes(){
        return explode(",",$this->parametros['value_types']);
    }

    public function deleteElementStruct($name){
        $this->gestorEstructura->deleteTree($name);
    }


    public function removeFirstRoot($string){

        return substr($string,strlen($this->parametros['root_name']));
    }


    public function validateStructName($name){
        return $this->gestorEstructura->validateName($name);
    }

    public  function printList($elemento,$showtype,$showid,$removeSlash,$showbuttons,$activarResaltado) {


        $idelement = $this->gestorEstructura->getId($elemento);

        if ($idelement == $activarResaltado) $ponerRojo=true;

        //<input type="radio" name="group1" value="Milk">
        //if ($showbuttons) $button = "<input type='submit' name='modif_".$idelement."' value='Modificar'><input type='submit' name='elim_".$idelement."' value='Eliminar'>";
        if ($showbuttons) {
            if ($ponerRojo)
            $button = "<input type='radio' name='group1' value='$idelement' CHECKED>";
            else $button = "<input type='radio' name='group1' value='$idelement'>";


            }
        else $button = "";


        if ($showtype) $meta_type = " <i>(".$this->gestorEstructura->getType($elemento).")</i>";
        else $meta_type = "";

        if ($showid) $meta_id = " <i>(id=".$this->gestorEstructura->getId($elemento).")</i>";
        else $meta_id = "";

        $array =$this->gestorEstructura->getInmChildren($elemento,false) ;
        if (count($array)==0) {
            if($removeSlash) {

                $mostrar = "<li>".$this->gestorEstructura->getRealName($elemento).$meta_type.$meta_id.$button."</li>";
                if ($ponerRojo) $mostrar = "<b>".$mostrar."</b>";
                echo $mostrar;

                }
            else {
                $mostrar= "<li>".$elemento.$meta_type.$meta_id.$button."</li>";
                if ($ponerRojo) $mostrar = "<b>".$mostrar."</b>";
                echo $mostrar;
            }
            return;
        }
        else {

            if($removeSlash) {
                $mostrar ="<li>".$this->gestorEstructura->getRealName($elemento).$meta_type.$meta_id.$button."<ul>";
            if ($ponerRojo) $mostrar = "<b>".$mostrar."</b>";
                echo $mostrar;

            }
            else {
                $mostrar= "<li>".$elemento.$meta_type.$meta_id.$button."<ul>";
            if ($ponerRojo) $mostrar = "<b>".$mostrar."</b>";
                echo $mostrar;

            }
            foreach ($array as $elemento2) {
                $this->printList($elemento2,$showtype,$showid,$removeSlash,$showbuttons,$activarResaltado);
            }
            echo "</ul></li>";
        }


    }

    /**
     *This function will load the elements from the XML into the database
     * @param <bool> $debug True to debug the function
     */
    function loadElements($debug=false) {
        $array = $this->gestorXML->getArrayElement();
        foreach ($array as $element) {
            if ($this->insertElement($element->getValue(),$element->getType(), $element->getParentName(),$element->getBrotherName(),$debug)) ;
        }
    }

    function printStructure() {
        $this->gestorEstructura->muestraArbol();
    }

    /**
     *This function will load the data from the XML into the database
     * @param <bool> $debug True to debug the function
     */
    function loadData($debug=false) {
        $array = $this->gestorXML->getArrayStruct();
        foreach ($array as $element) {
            if ($this->addChild($element->getValue(),$element->getType(), $element->getParentName(),$element->getBrotherName(),$debug)) ;
        }
    }

    /**
     *This function will load the XML structure and generate all the nodes contained in itself.
     * @param <string> $fileName String with the path to the filename
     */
    function loadXML($fileName) {
        $this->gestorXML->loadXML($fileName);
//        echo "xml cargado <br>";
        $this->gestorXML->generateNodes();
    }

    /**
     *This function returns the array "params" that contains all the characters used.
     * @return <array> array of data with the parameters of the class
     */
    function getParams() {
        return $this->parametros;
    }

    /**
     *This function returns all different values from a given path. For example, is the
     * path is /SISTEMA/ACTIVIDAD/ESCALA, it returns all the differents values from ESCALA
     * @param <string> $path String with the path of the data to retrieve.
     * @param <bool> $debug Var to debug the function.
     * @return <array> Array with the values.
     */
    function getValuesFromPath($path, $debug) {
        return $this->gestorDatos->getValuesFromPath($path,$this->gestorEstructura,$debug=false);
    }

    /**
     * This function will print all the nodes from the struct, not from  the database but from the
     * internal structure of the XML
     */
    function printArraysXML() {
        $this->gestorXML->printArraysStruct();
        echo "<br> ahora imprimimos elementos<br>";
        $this->gestorXML->printArraysElement();
        echo "<br>ahora imprimimos datos<br>";
        $this->gestorXML->printArraysData();
    }

    /**
     * This function return a value of an attribute especified in $path
     * If the attribute doesn't exist returns NULL
     * @param string $path contains the path to the attribute.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return mixed
     */
    public function getValue($path,$debug=false) {
        return $this->gestorDatos->getValue($path,$this->gestorElementos,$this->gestorEstructura,$this->gestorRelaciones,$debug);
    }


    /**
     * This function sets the value of an attribute.
     * If the attribute doesn't exist returns false.
     * @param string $path contains the path to the attribute.
     * @param mixed $value contains the value to set.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return boolean
     */
    public function setValue($path,$value,$debug=false) {
//        echo "ruta a insertar en setvalue:".$path."<br>";
//        echo "valor a insertar en setvalue:".$value."<br>";
        return $this->gestorDatos->setValue($path,$value,$this->gestorElementos,$this->gestorEstructura,$this->gestorRelaciones,$debug);
    }


    /**
     * This function deletes a value of an attribute.
     * If the attribute doesn't exist returns false.
     * @param string $path contains the path to the attribute.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return boolean
     */
    public function deleteValue($path,$debug=false) {
        return $this->gestorDatos->deleteValue($path,$this->gestorElementos,$this->gestorEstructura,$this->gestorRelaciones,$debug);
    }


    /**
     * This function inserts a new element.
     * @param string $type contains an element type.
     * @param string $name contains the name of the element to insert.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return boolean
     */
    public function insertElement($type,$name,$debug=false) {
        return $this->gestorElementos->insert($type, $name,$this->gestorEstructura,$debug);
    }


    /**
     * This function deletes an element and all its data.
     * @param string $name contains the name of the element to delete.
     * @param string $type contains the type of the element to delete.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return boolean
     */
    public function deleteElement($name,$type,$debug=false) {
        $this->gestorDatos->deleteValuesById($this->gestorElementos->getId($name,$type),$debug);
        return $this->gestorElementos->delete($name,$type,$debug);
    }

    /**
     *This function creates a relation between two elements
     * @param <string> $name String with the two elements separated by a slash
     * @param <bool> $debug var to debug
     * @return <type> it returns the id of the created relation
     */
    public function createRelation($name,$debug=false) {
        return $this->gestorRelaciones->createRelation($name, $this->gestorEstructura,$this->gestorElementos, $debug);
    }
    /**
     *This function deletes a relation between two elements
     * @param <string> $name String with the two elements separated by a slash
     * @param <bool> $debug var to debug
     * @return <type> true if the delete was correct
     */
    public function deleteRelation($name,$debug=false) {
        return $this->gestorRelaciones->delete($name, $debug);
    }
    /**
     *This function returns the strings that match the regular expresion given by param
     * @param <string> $name Regular expresion to match
     * @param <bool> $debug var to debug
     * @return <array> Array with the results
     */
    public function getRelation($name,$debug=false) {
        return $this->gestorRelaciones->getRelation($name);
    }

    /**
     * This function returns the ID of an element specified by $name.
     * @param string $name contains the name of the element.
     * @param string $type contains the type of the element.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return integer with theid
     */
    public function getId($name,$type,$debug=false) {
        return $this->gestorElementos->getId($name,$type,$debug);
    }

    /**
     *This function returns an array containing all the elements of a given type.
     * @param <string> $nombretipo String with the type
     * @param <bool> $debug var to debug
     * @return <array> Array with the results
     */
    public function getElementsByType($nombretipo,$debug=false) {
        return $this->gestorElementos->getNamesFromType($nombretipo);
    }

    /**
     *
     * @param <type> $array
     * @param <type> $debug
     * @return <type>
     */
    public function getIdsByProperty($array,$debug = false) {
        return $this->gestorDatos->getIdsByProperty($array,$this->gestorEstructura,$this->parametros,$debug);
    }


    /**
     *This function transforms an array with ids into an array with the names of the ids.
     * @param <array> $arrayIDS Array with the ids of the elements to transform
     * @return <array> Array with the names
     */
    public function getElementNameFromIds($arrayIDS) {
        $newarray= array();
        foreach($arrayIDS as $element) {
            $newarray[]= $this->gestorElementos->getNameId($element);
        }
        return $newarray;
    }

    /**
     *This function return the name of an element with a given id
     * @param <string> $elementName String with the element's name.
     * @return <string> String with the id
     */
    public function getNameElementId($elementid) {
        return $this->gestorElementos->getNameId($elementid);
    }


    public function getNameStructId($structid){
        return $this->gestorEstructura->getName($structid);
    }

    /**
     *This function checks if a relation exists.
     * @param <string> $name String with the name of the relation
     * @return <bool> True if exists, false otherwise.
     */
    public function existsRelation($name) {
        return $this->gestorRelaciones->exists($name);
    }

    /**
     *This function checks if an element exists.
     * @param <string> $name String with the name of the element
     * @return <bool> True if exists, false otherwise.
     */
    public function existsElement($elementName) {
        return $this->gestorElementos->exists($elementName);
    }

    /**
     *This function returns all the nodes below from a given node.
     * @param <string> $nodeRoot Name of the root node.
     * @param <bool> $completePath If true, the complete path is returned. Otherwise
     * it returns only the last part of the path.
     * @return <array> Array with all the nodes.
     */
    public function getAllNodes($nodeRoot,$completePath) {
        return $this->gestorEstructura->getAllNodes($nodeRoot,$completePath);
    }

    /**
     * This function will be deleted from this class.
     * @TODO replace this function with XML load functions.
     * @deprecated
     */
    public function addChild($nombreNodo,$tipo, $nombrePadre, $nombreHermano,$debug=false) {
        if ($nombreHermano=="") {
            $np=$this->parametros['root_name'].$nombrePadre;
            $nh="";
        }else {
            $np="";
            $nh=$this->parametros['root_name'].$nombreHermano;
        }
        return $this->gestorEstructura->addChild($nombreNodo, $tipo, $np, $nh,$debug);
    }

    /**
     * This function initializes an empty structure.
     * @param boolean $debug OPTIONAL parameter to show debug messages.
     * @return boolean
     */
    public function initializeStruct($debug=false) {
        return $this->gestorEstructura->addChild(substr($this->parametros['root_name'],1),INTERNAL_NODES_TYPE_NAME,"","",$debug);
    }
}
?>
